package de.zainodis.commons.component;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

public class Entity implements IEntity {

   /**
    * Components this widget aggregates. The CopyOnWriteArrayList is used to
    * warrant thread-safety.
    */
   private List<Component> components;

   /**
    * Creates a thread-safe new entity, which keeps it's component in a
    * {@link CopyOnWriteArrayList}.
    */
   public Entity() {
	 this(true);
   }

   /**
    * For multi-threaded environments it is recommended to use the empty default
    * constructor or pass true in this constructor.
    * 
    * @param makeThreadSafe
    *           if set to true, the list of components is made thread-safe; if
    *           false, the list of components is not thread safe.
    */
   public Entity(boolean makeThreadSafe) {
	 if (makeThreadSafe) {
	    components = new CopyOnWriteArrayList<Component>();
	 } else {
	    components = new ArrayList<Component>();
	 }
   }

   @Override
   public void addComponent(Component component) {
	 // Only non-null components are added
	 if (component != null) {
	    if (!components.contains(component)) {
		  components.add(component);
	    }
	 }
   }

   @Override
   public void removeComponent(Component component) {
	 if (components.remove(component)) {
	    // Call cleanup method of component
	    component.onRemove();
	 }
   }

   @Override
   public <T extends Component> T getComponent(Class<T> requested) {
	 // This won't return the right type, if requested is specified as
	 // the general super interface IComponent. Not ideal, but list doesn't
	 // offer more, map is an option but possibly overkill
	 for (IComponent component : components) {
	    // Comparing classes would be more precise but also more limiting
	    if (requested.isAssignableFrom(component.getClass())) {
		  return requested.cast(component);
	    }
	 }
	 return null;
   }

   @Override
   public Iterator<Component> getComponents() {
	 return components.iterator();
   }

   @Override
   public void clearComponents() {
	 if (components != null) {
	    int numberOfCompoents = components.size();
	    for (int i = numberOfCompoents - 1; i >= 0; i--) {
		  removeComponent(components.get(i));
	    }
	 }
   }
}
